/*
 * jxUtils Project (2014)
 * 
 * by Denilson Edinaldo Pinto
 * 
 * LGPL
 * Copyright (C) 2014
 * 
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU Lesser General Public License for more details.
 * 
 * You should have received a copy of the GNU Lesser General Public License
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
 */
package org.jxUtils.image;

import static org.jxUtils.system.ScreenUtil.getPrintScreen;
import static org.jxUtils.system.ScreenUtil.getScreenSize;

import java.awt.AWTException;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.RenderingHints;
import java.awt.Window;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.image.BufferedImage;
import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStream;
import java.net.URISyntaxException;
import java.net.URL;

import javax.imageio.ImageIO;
import javax.swing.Icon;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JLabel;
import javax.swing.JWindow;

import org.jxUtils.check.CheckUtil;
import org.jxUtils.check.ParameterCheck;
import org.jxUtils.file.JXFile;
import org.jxUtils.file.type.ImageType;
import org.jxUtils.file.type.SimpleTextType;
import org.jxUtils.image.filter.NegativeFilter;

import sun.awt.image.ImageFormatException;
import sun.swing.plaf.synth.SynthIcon;

import com.sun.java.swing.plaf.windows.WindowsInternalFrameTitlePane.ScalableIconUIResource;

/**
 * @author Denilson Edinaldo Pinto
 * @porject jxUtils
 * @package org.jxUtils.image
 * @date 08/02/2014 - 11:39:39
 */
public final class ImageUtil {
	
	/**
	 * @param imageIcon
	 * @param format
	 * @return imageIcon in byte array or null
	 */
	private static byte[] toByteArray(ImageIcon imageIcon, String format) {
	
		ParameterCheck.isNullOrAbsoluteEmpty(format, "format");
		
		//
		if(imageIcon != null) {
			
			//
			try (ByteArrayOutputStream outputStream = new ByteArrayOutputStream()) {
				
				ImageIO.write(newBufferedImage(imageIcon), format, outputStream);
				
				return outputStream.toByteArray();
				
			}catch(Throwable throwable) {
				
				throwable.printStackTrace();
			}
		}
		
		return null;
	}
	
	/**
	 * @param bufferedImage
	 * @return coped BufferedImage
	 */
	public static BufferedImage copy(final BufferedImage bufferedImage) {
	
		return copy(bufferedImage, BufferedImage.TYPE_INT_RGB);
	}
	
	/**
	 * @param bufferedImage
	 * @param imageType
	 * @return coped BufferedImage
	 */
	public static BufferedImage copy(final BufferedImage bufferedImage, final int imageType) {
	
		BufferedImage newBufferedImage = null;
		
		//
		if(bufferedImage != null) {
			
			newBufferedImage = newImage(bufferedImage, imageType);
			
			newBufferedImage.setData(bufferedImage.getRaster());
		}
		
		return newBufferedImage;
	}
	
	/**
	 * @param imageIcon
	 * @return coped BufferedImage
	 */
	public static BufferedImage copy(final ImageIcon imageIcon) {
	
		return copy(imageIcon, BufferedImage.TYPE_INT_RGB);
	}
	
	/**
	 * @param imageIcon
	 * @param imageType
	 * @return coped BufferedImage
	 */
	public static BufferedImage copy(final ImageIcon imageIcon, final int imageType) {
	
		BufferedImage newBufferedImage = null;
		
		//
		if(imageIcon != null) {
			
			newBufferedImage = newImage(imageIcon.getIconWidth(), imageIcon.getIconHeight(), imageType);
			
			final Graphics graphics = newBufferedImage.createGraphics();
			
			graphics.setColor(Color.WHITE);
			graphics.fillRect(0, 0, imageIcon.getIconWidth(), imageIcon.getIconHeight());
			
			imageIcon.paintIcon(null, graphics, 0, 0);
			
			graphics.dispose();
		}
		
		return newBufferedImage;
	}
	
	/**
	 * @param bufferedImage
	 * @param x
	 * @param y
	 * @param width
	 * @param height
	 * @param color
	 */
	public static void drawEllipse(BufferedImage bufferedImage, int x, int y, int width, int height, Color color) {
	
		Color old = bufferedImage.getGraphics().getColor();
		
		bufferedImage.getGraphics().setColor(color);
		
		bufferedImage.getGraphics().drawOval(x, y, width, height);
		
		bufferedImage.getGraphics().setColor(old);
	}
	
	/**
	 * @param bufferedImage
	 * @param x
	 * @param y
	 * @param width
	 * @param height
	 * @param rgb
	 */
	public static void drawEllipse(BufferedImage bufferedImage, int x, int y, int width, int height, int[] rgb) {
	
		drawEllipse(bufferedImage, x, y, width, height, new Color(rgb[0], rgb[1], rgb[2]));
	}
	
	/**
	 * @param bufferedImage
	 * @param x
	 * @param y
	 * @param width
	 * @param height
	 * @param color
	 */
	public static void drawFilledEllipse(BufferedImage bufferedImage, int x, int y, int width, int height, Color color) {
	
		Color old = bufferedImage.getGraphics().getColor();
		
		bufferedImage.getGraphics().setColor(color);
		
		bufferedImage.getGraphics().fillOval(x, y, width, height);
		
		bufferedImage.getGraphics().setColor(old);
	}
	
	/**
	 * @param bufferedImage
	 * @param x
	 * @param y
	 * @param width
	 * @param height
	 * @param rgb
	 */
	public static void drawFilledEllipse(BufferedImage bufferedImage, int x, int y, int width, int height, int[] rgb) {
	
		drawEllipse(bufferedImage, x, y, width, height, new Color(rgb[0], rgb[1], rgb[2]));
	}
	
	/**
	 * @param bufferedImage
	 * @param x
	 * @param y
	 * @param width
	 * @param height
	 * @param color
	 */
	public static void drawFilledRect(BufferedImage bufferedImage, int x, int y, int width, int height, Color color) {
	
		Color old = bufferedImage.getGraphics().getColor();
		
		bufferedImage.getGraphics().setColor(color);
		
		bufferedImage.getGraphics().fillRect(x, y, width, height);
		
		bufferedImage.getGraphics().setColor(old);
	}
	
	/**
	 * @param bufferedImage
	 * @param x
	 * @param y
	 * @param width
	 * @param height
	 * @param rgb
	 */
	public static void drawFilledRect(BufferedImage bufferedImage, int x, int y, int width, int height, int[] rgb) {
	
		drawFilledRect(bufferedImage, x, y, width, height, new Color(rgb[0], rgb[1], rgb[2]));
	}
	
	/**
	 * @param bufferedImage
	 * @param x
	 * @param y
	 * @param size
	 * @param color
	 */
	public static void drawFilledSquare(BufferedImage bufferedImage, int x, int y, int size, Color color) {
	
		drawFilledRect(bufferedImage, x, y, size, size, color);
	}
	
	/**
	 * @param bufferedImage
	 * @param x
	 * @param y
	 * @param size
	 * @param rgb
	 */
	public static void drawFilledSquare(BufferedImage bufferedImage, int x, int y, int size, int[] rgb) {
	
		drawFilledSquare(bufferedImage, x, y, size, new Color(rgb[0], rgb[1], rgb[2]));
	}
	
	/**
	 * @param bufferedImage
	 * @param xBegin
	 * @param yBegin
	 * @param xEnd
	 * @param yEnd
	 * @param color
	 */
	public static void drawLine(BufferedImage bufferedImage, int xBegin, int yBegin, int xEnd, int yEnd, Color color) {
	
		Color old = bufferedImage.getGraphics().getColor();
		
		bufferedImage.getGraphics().setColor(color);
		
		bufferedImage.getGraphics().drawLine(xBegin, xBegin, xEnd, yEnd);;
		
		bufferedImage.getGraphics().setColor(old);
	}
	
	/**
	 * @param bufferedImage
	 * @param xBegin
	 * @param yBegin
	 * @param xEnd
	 * @param yEnd
	 * @param rgb
	 */
	public static void drawLine(BufferedImage bufferedImage, int xBegin, int yBegin, int xEnd, int yEnd, int rgb[]) {
	
		drawLine(bufferedImage, xBegin, yBegin, xEnd, yEnd, new Color(rgb[0], rgb[1], rgb[2]));
	}
	
	/**
	 * @param bufferedImage
	 * @param x
	 * @param y
	 * @param width
	 * @param height
	 * @param color
	 */
	public static void drawRect(BufferedImage bufferedImage, int x, int y, int width, int height, Color color) {
	
		Color old = bufferedImage.getGraphics().getColor();
		
		bufferedImage.getGraphics().setColor(color);
		
		bufferedImage.getGraphics().drawRect(x, y, width, height);
		
		bufferedImage.getGraphics().setColor(old);
	}
	
	/**
	 * @param bufferedImage
	 * @param x
	 * @param y
	 * @param width
	 * @param height
	 * @param rgb
	 */
	public static void drawRect(BufferedImage bufferedImage, int x, int y, int width, int height, int[] rgb) {
	
		drawRect(bufferedImage, x, y, width, height, new Color(rgb[0], rgb[1], rgb[2]));
	}
	
	/**
	 * @param bufferedImage
	 * @param x
	 * @param y
	 * @param size
	 * @param color
	 */
	public static void drawSquare(BufferedImage bufferedImage, int x, int y, int size, Color color) {
	
		drawRect(bufferedImage, x, y, size, size, color);
	}
	
	/**
	 * @param bufferedImage
	 * @param x
	 * @param y
	 * @param size
	 * @param rgb
	 */
	public static void drawSquare(BufferedImage bufferedImage, int x, int y, int size, int[] rgb) {
	
		drawSquare(bufferedImage, x, y, size, new Color(rgb[0], rgb[1], rgb[2]));
	}
	
	/**
	 * @param value
	 * @return value
	 */
	public static int isPixel(final int value) {
	
		return value < 0 ? 0 : value > 255 ? 255 : value;
	}
	
	/**
	 * @param imageFile
	 * @return bufferedImage
	 * @throws IOException
	 */
	public static BufferedImage loadImage(final File imageFile) throws IOException {
	
		ParameterCheck.isNull(imageFile, "imageFile");
		
		return ImageIO.read(imageFile);
	}
	
	/**
	 * @param imageFile
	 * @return imageIcon
	 * @throws IOException
	 */
	public static ImageIcon loadImageIcon(final File imageFile) throws IOException {
	
		final ImageIcon imageIcon = new ImageIcon(loadImage(imageFile));
		
		imageIcon.setDescription(imageFile.getName());
		
		return imageIcon;
	}
	
	/**
	 * @param component
	 * @param text
	 * @param toolTipText
	 * @param owner
	 * @return {@link JButton} with Icon to {@link JComponent}
	 * @throws AWTException
	 */
	public static JButton makeButtonIcon(JComponent component, String text, String toolTipText, Window owner) throws AWTException {
	
		//
		ImageIcon imageIcon = new ImageIcon();
		ImageIcon icon = new ImageIcon();
		
		//
		imageIcon = getPrintScreen(component);
		icon = resizeImage(imageIcon, 35, -1);
		
		//
		JButton button = new JButton(text, icon);
		button.setPreferredSize(new Dimension(50, 35));
		button.setToolTipText(toolTipText);
		
		//
		final JWindow window = new JWindow(owner);
		
		// Tamanho original do component
		Dimension dimension = new Dimension((int)(component.getPreferredSize().getWidth()), (int)(component.getPreferredSize().getHeight()));
		
		window.setPreferredSize(dimension);
		window.setSize(dimension);
		window.add(new JLabel(resizeImage(imageIcon, (window.getWidth() - 20), -1)), BorderLayout.CENTER);
		
		//
		button.addMouseListener(new MouseAdapter() {
			
			@Override
			public void mouseEntered(MouseEvent mouseEvent) {
			
				int halfWidthWin = (window.getWidth() / 2);
				int x = mouseEvent.getXOnScreen() - halfWidthWin;
				int y = mouseEvent.getYOnScreen() - window.getHeight();
				
				x = x < 0 ? 0 : x;
				y = y < 0 ? 0 : y;
				
				//
				if((x + window.getWidth()) > getScreenSize().getWidth()) {
					
					x = (int)(getScreenSize().getWidth() - window.getWidth());
				}
				
				window.setLocation(x, y);
				window.setVisible(true);
			}
			
			@Override
			public void mouseExited(MouseEvent mouseEvent) {
			
				window.dispose();
			}
		});
		
		return button;
	}
	
	/**
	 * width = 30
	 * height = 30
	 * 
	 * @param file
	 * @return {@link ImageIcon} Preview or System Icon or null
	 */
	public static ImageIcon makePreviewToFile(File file) {
	
		return makePreviewToFile(file, 30, 30);
	}
	
	/**
	 * @param file
	 * @param dimension
	 * @return {@link ImageIcon} Preview or System Icon or null
	 */
	public static ImageIcon makePreviewToFile(File file, Dimension dimension) {
	
		return makePreviewToFile(file, new Double(dimension.getWidth()).intValue(), new Double(dimension.getHeight()).intValue());
	}
	
	/**
	 * @param file
	 * @param width
	 *        >= 5
	 * @param height
	 *        >= 5
	 * @return {@link ImageIcon} Preview or System Icon or null
	 */
	public static ImageIcon makePreviewToFile(File file, int width, int height) {
	
		ParameterCheck.isNull(file, "file");
		
		try {
			//
			if(file.isFile()) {
				
				final String fullExtension = JXFile.getFullExtension(file);
				
				//
				if( !fullExtension.trim().isEmpty()) {
					
					//
					if(ImageType.containsInAny(fullExtension)) {
						
						final ImageIcon preview = ImageUtil.loadImageIcon(file);
						
						//
						if(preview.getIconWidth() == width && preview.getIconHeight() == height) {
							
							return preview;
							
						}else {
							
							return ImageUtil.resizeImage(preview, width, height);
						}
						
					}else if(SimpleTextType.containsInAny(fullExtension)) {
						
						final BufferedImage bufferedImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
						
						//
						try (BufferedReader reader = new BufferedReader(new FileReader(file))) {
							
							String line = "";
							
							int x = 10;
							int y = 0;
							int count = 0;
							
							//
							while(CheckUtil.isNotNull(line = reader.readLine()) && count < Math.ceil(height * 0.066)) {
								
								y = y + 15;
								
								bufferedImage.getGraphics().drawString(line, x, y);
								
								count++;
							}
							
							return NegativeFilter.apply(bufferedImage);
							
						}catch(Throwable throwable) {
							
							throwable.printStackTrace();
						}
					}
				}
			}
			
			return ImageUtil.resizeImage(JXFile.getIcon(file), width, height);
			
		}catch(Throwable throwable) {
			
			throwable.printStackTrace();
		}
		
		return null;
	}
	
	/**
	 * width = 30
	 * height = 30
	 * 
	 * @param path
	 * @return {@link ImageIcon} Preview or System Icon or null
	 * @throws URISyntaxException
	 */
	public static ImageIcon makePreviewToURL(URL path) throws URISyntaxException {
	
		ParameterCheck.isNullOrEmpty(path, "path");
		
		return makePreviewToFile(new File(path.toURI()));
	}
	
	/**
	 * @param path
	 * @param width
	 * @param height
	 * @return {@link ImageIcon} Preview or System Icon or null
	 * @throws URISyntaxException
	 */
	public static ImageIcon makePreviewToURL(URL path, int width, int height) throws URISyntaxException {
	
		ParameterCheck.isNullOrEmpty(path, "path");
		
		return makePreviewToFile(new File(path.toURI()), width, height);
	}
	
	/**
	 * @param imageIcon
	 * @return new BufferedImage
	 */
	public static BufferedImage newBufferedImage(final ImageIcon imageIcon) {
	
		return newBufferedImage(imageIcon, Color.WHITE);
	}
	
	/**
	 * @param imageIcon
	 * @param color
	 * @return new BufferedImage
	 */
	public static BufferedImage newBufferedImage(final ImageIcon imageIcon, final Color color) {
	
		BufferedImage newBufferedImage = null;
		
		//
		if(imageIcon != null) {
			
			newBufferedImage = newImage(imageIcon.getIconWidth(), imageIcon.getIconHeight(), BufferedImage.TYPE_INT_RGB);
			
			final Graphics graphics = newBufferedImage.createGraphics();
			
			graphics.setColor(color != null ? color : Color.WHITE);
			graphics.fillRect(0, 0, imageIcon.getIconWidth(), imageIcon.getIconHeight());
			
			imageIcon.paintIcon(null, graphics, 0, 0);
			
			graphics.dispose();
		}
		
		return newBufferedImage;
	}
	
	/**
	 * @param width
	 * @param height
	 * @return new BufferedImage
	 */
	public static BufferedImage newBufferedImage(final int width, final int height) {
	
		return newBufferedImage(width, height, BufferedImage.TYPE_INT_RGB, Color.WHITE);
	}
	
	/**
	 * @param width
	 * @param height
	 * @param color
	 * @return new BufferedImage
	 */
	public static BufferedImage newBufferedImage(final int width, final int height, final Color color) {
	
		return newBufferedImage(width, height, BufferedImage.TYPE_INT_RGB, color);
	}
	
	/**
	 * @param width
	 * @param height
	 * @param imageType
	 * @param color
	 * @return new BufferedImage
	 */
	public static BufferedImage newBufferedImage(final int width, final int height, final int imageType, final Color color) {
	
		final BufferedImage bufferedImage = newImage(width, height, BufferedImage.TYPE_INT_RGB);
		
		final Graphics graphics = bufferedImage.createGraphics();
		
		graphics.setColor(color != null ? color : Color.WHITE);
		graphics.fillRect(0, 0, width, height);
		
		final ImageIcon imageIcon = new ImageIcon();
		
		imageIcon.paintIcon(null, graphics, 0, 0);
		
		graphics.dispose();
		
		return bufferedImage;
	}
	
	/**
	 * @param bufferedImage
	 * @return new BufferedImage
	 */
	public static BufferedImage newImage(final BufferedImage bufferedImage) {
	
		return newImage(bufferedImage, BufferedImage.TYPE_INT_RGB);
	}
	
	/**
	 * @param bufferedImage
	 * @param imageType
	 * @return new BufferedImage
	 */
	public static BufferedImage newImage(final BufferedImage bufferedImage, final int imageType) {
	
		BufferedImage newBufferedImage = null;
		
		//
		if(bufferedImage != null) {
			
			newBufferedImage = newImage(bufferedImage.getWidth(), bufferedImage.getHeight(), imageType);
		}
		
		return newBufferedImage;
	}
	
	/**
	 * @param width
	 * @param height
	 * @return new BufferedImage
	 */
	public static BufferedImage newImage(final int width, final int height) {
	
		return newImage(width, height, BufferedImage.TYPE_INT_RGB);
	}
	
	/**
	 * @param width
	 * @param height
	 * @param imageType
	 * @return new BufferedImage
	 */
	public static BufferedImage newImage(final int width, final int height, final int imageType) {
	
		return new BufferedImage(width, height, imageType);
	}
	
	/**
	 * @param image
	 * @param newWidth
	 * @param newHeight
	 * @return new ImageIcon resized
	 */
	public static ImageIcon resizeImage(final Image image, final int newWidth, final int newHeight) {
	
		ParameterCheck.isNull(image, "image");
		
		return new ImageIcon(image.getScaledInstance(newWidth, newHeight, Image.SCALE_DEFAULT));
	}
	
	/**
	 * @param imageIcon
	 * @param newWidth
	 * @param newHeight
	 * @return new ImageIcon resized
	 */
	public static ImageIcon resizeImage(final ImageIcon imageIcon, final int newWidth, final int newHeight) {
	
		ParameterCheck.isNull(imageIcon, "imageIcon");
		
		final ImageIcon newImageIcon = resizeImage(imageIcon.getImage(), newWidth, newHeight);
		
		newImageIcon.setDescription(imageIcon.getDescription());
		
		return newImageIcon;
	}
	
	/**
	 * <table border="1" summary="Image format advantages and disadvantages">
	 * <tr>
	 * <th id="h1">Format</th>
	 * <th id="h2">Plus</th>
	 * <th id="h3">Minus</th>
	 * </tr>
	 * <tr>
	 * <td headers="h1">GIF</td>
	 * <td headers="h2">Supports animation, and transparent pixels</td>
	 * <td headers="h3">Supports only 256 colors and no translucency</td>
	 * </tr>
	 * <tr>
	 * <td headers="h1">PNG</td>
	 * <td headers="h2">Better alternative than GIF or JPG for high colour lossless images, supports translucency</td>
	 * <td headers="h3">Doesn&#39;t support animation</td>
	 * </tr>
	 * <tr>
	 * <td headers="h1">JPG</td>
	 * <td headers="h2">Great for photographic images</td>
	 * <td headers="h3">Loss of compression, not good for text, screenshots, or any application where the original image must be preserved exactly</td>
	 * </tr>
	 * </table>
	 * 
	 * @param image
	 * @param outFile
	 * @param outFormatName
	 * @throws ImageFormatException
	 * @throws IOException
	 */
	public static void saveImage(final BufferedImage image, final File outFile, final String outFormatName) throws ImageFormatException, IOException {
	
		ParameterCheck.isNull(image, "image");
		ParameterCheck.isNull(outFile, "outFile");
		ParameterCheck.isNullOrAbsoluteEmpty(outFormatName, "outFormatName");
		
		//
		if( !outFile.exists()) {
			
			outFile.createNewFile();
		}
		
		ImageIO.write(image, outFormatName.trim(), new FileOutputStream(outFile));
	}
	
	/**
	 * <table border="1" summary="Image format advantages and disadvantages">
	 * <tr>
	 * <th id="h1">Format</th>
	 * <th id="h2">Plus</th>
	 * <th id="h3">Minus</th>
	 * </tr>
	 * <tr>
	 * <td headers="h1">GIF</td>
	 * <td headers="h2">Supports animation, and transparent pixels</td>
	 * <td headers="h3">Supports only 256 colors and no translucency</td>
	 * </tr>
	 * <tr>
	 * <td headers="h1">PNG</td>
	 * <td headers="h2">Better alternative than GIF or JPG for high colour lossless images, supports translucency</td>
	 * <td headers="h3">Doesn&#39;t support animation</td>
	 * </tr>
	 * <tr>
	 * <td headers="h1">JPG</td>
	 * <td headers="h2">Great for photographic images</td>
	 * <td headers="h3">Loss of compression, not good for text, screenshots, or any application where the original image must be preserved exactly</td>
	 * </tr>
	 * </table>
	 * 
	 * @param image
	 * @param outFile
	 * @param outFormatName
	 * @throws ImageFormatException
	 * @throws IOException
	 */
	public static void saveImage(final ImageIcon image, final File outFile, final String outFormatName) throws ImageFormatException, IOException {
	
		saveImage(copy(image), outFile, outFormatName);
	}
	
	/**
	 * @param imageIcon
	 * @return imageIcon in JPEG byte array or null
	 */
	public static byte[] toByteArray(ImageIcon imageIcon) {
	
		return toByteArrayJPEG(imageIcon);
	}
	
	/**
	 * @param imageIcon
	 * @return imageIcon in byte array or null
	 */
	public static byte[] toByteArrayGIF(ImageIcon imageIcon) {
	
		return toByteArray(imageIcon, "GIF");
	}
	
	/**
	 * @param imageIcon
	 * @return imageIcon in byte array or null
	 */
	public static byte[] toByteArrayJPEG(ImageIcon imageIcon) {
	
		return toByteArray(imageIcon, "JPG");
	}
	
	/**
	 * @param imageIcon
	 * @return imageIcon in byte array or null
	 */
	public static byte[] toByteArrayPNG(ImageIcon imageIcon) {
	
		return toByteArray(imageIcon, "PNG");
	}
	
	/**
	 * @param imageFile
	 * @param gifFile
	 * @throws IOException
	 * @throws ImageFormatException
	 */
	public static void toGIF(final File imageFile, final File gifFile) throws ImageFormatException, IOException {
	
		saveImage(loadImage(imageFile), gifFile, "GIF");
	}
	
	/**
	 * @param data
	 * @return byte array in {@link ImageIcon} or null
	 */
	public static ImageIcon toImageIcon(byte[] data) {
	
		//
		if(CheckUtil.isNotNullAndNotEmpty(data)) {
			
			//
			try (InputStream inputStream = new ByteArrayInputStream(data)) {
				
				return new ImageIcon(ImageIO.read(inputStream));
				
			}catch(Throwable throwable) {
				
				throwable.printStackTrace();
			}
		}
		
		return null;
	}
	
	/**
	 * @param icon
	 * @return {@link ImageIcon} or null
	 */
	public static ImageIcon toImageIcon(Icon icon) {
	
		ImageIcon imageIcon = null;
		
		//
		if(icon != null) {
			
			//
			if(icon instanceof ImageIcon) {
				
				imageIcon = (ImageIcon)icon;
				
			}else if(icon instanceof ScalableIconUIResource) {
				
				final ScalableIconUIResource scalableIconUIResource = (ScalableIconUIResource)icon;
				
				imageIcon = new ImageIcon(ImageUtil.newBufferedImage(scalableIconUIResource.getIconWidth(), scalableIconUIResource.getIconHeight()));
				
				scalableIconUIResource.paintIcon(null, imageIcon.getImage().getGraphics(), 0, 0);
				
			}else if(icon instanceof SynthIcon) {
				
				final SynthIcon synthIcon = (SynthIcon)icon;
				
				imageIcon = new ImageIcon(ImageUtil.newBufferedImage(synthIcon.getIconWidth(), synthIcon.getIconHeight()));
				
				synthIcon.paintIcon(null, imageIcon.getImage().getGraphics(), 0, 0);
			}
		}
		
		return imageIcon;
	}
	
	/**
	 * @param imageFile
	 * @param jpegFile
	 * @throws IOException
	 * @throws ImageFormatException
	 */
	public static void toJPEG(final File imageFile, final File jpegFile) throws ImageFormatException, IOException {
	
		saveImage(loadImage(imageFile), jpegFile, "JPG");
	}
	
	/**
	 * @param imageFile
	 * @param pngFile
	 * @throws IOException
	 * @throws ImageFormatException
	 */
	public static void toPNG(final File imageFile, final File pngFile) throws ImageFormatException, IOException {
	
		saveImage(loadImage(imageFile), pngFile, "PNG");
	}
	
	/**
	 * @param imageFile
	 * @param thumbnailFile
	 * @param thumbWidth
	 * @param thumbHeight
	 * @param quality
	 * @throws Exception
	 */
	public static void toThumbnail(final File imageFile, final File thumbnailFile, int thumbWidth, int thumbHeight, final int quality) throws Exception {
	
		ImageIO.write(toThumbnail(imageFile, thumbWidth, thumbHeight, quality), "JPG", thumbnailFile);
	}
	
	/**
	 * @param imageFile
	 * @param thumbWidth
	 * @param thumbHeight
	 * @param quality
	 * @return {@link BufferedImage}
	 * @throws Exception
	 */
	public static BufferedImage toThumbnail(final File imageFile, int thumbWidth, int thumbHeight, final int quality) throws Exception {
	
		ParameterCheck.isNull(imageFile, "imageFile");
		
		final Image image = ImageIO.read(imageFile);
		
		final int imageWidth = image.getWidth(null);
		final int imageHeight = image.getHeight(null);
		
		final double thumbRatio = (double)thumbWidth / (double)thumbHeight;
		final double imageRatio = (double)imageWidth / (double)imageHeight;
		
		//
		if(thumbRatio < imageRatio) {
			
			thumbHeight = (int)(thumbWidth / imageRatio);
			
		}else {
			
			thumbWidth = (int)(thumbHeight * imageRatio);
		}
		
		//
		if(imageWidth < thumbWidth && imageHeight < thumbHeight) {
			
			thumbWidth = imageWidth;
			thumbHeight = imageHeight;
			
		}else if(imageWidth < thumbWidth) {
			
			thumbWidth = imageWidth;
			
		}else if(imageHeight < thumbHeight) {
			
			thumbHeight = imageHeight;
		}
		
		final BufferedImage thumbImage = new BufferedImage(thumbWidth, thumbHeight, BufferedImage.TYPE_INT_RGB);
		
		final Graphics2D graphics2D = thumbImage.createGraphics();
		
		graphics2D.setBackground(Color.WHITE);
		graphics2D.setPaint(Color.WHITE);
		graphics2D.fillRect(0, 0, thumbWidth, thumbHeight);
		graphics2D.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
		graphics2D.drawImage(image, 0, 0, thumbWidth, thumbHeight, null);
		
		return thumbImage;
	}
	
	/**
	 * @param imageFile
	 * @param thumbWidth
	 * @param thumbHeight
	 * @param quality
	 * @return {@link ImageIcon}
	 * @throws Exception
	 */
	public static ImageIcon toThumbnailIcon(final File imageFile, int thumbWidth, int thumbHeight, final int quality) throws Exception {
	
		return new ImageIcon(toThumbnail(imageFile, thumbWidth, thumbHeight, quality));
	}
}
